package com.googlecode.continuity.core.server.service;

import java.util.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import com.googlecode.continuity.core.client.ConfigurationEntry;
import com.googlecode.continuity.core.server.SimplePropertiesPersister;

/**
 * ConfigurationServiceProperties
 * <p/>
 * TODO: init properties check
 *
 * @author Peter Schmitt <aragos@aragos.de>
 */
public class ConfigurationServiceProperties implements ConfigurationService {
// ------------------------------ FIELDS ------------------------------

  private static final String PROPERTIES_SUFFIX = ".properties";
  private static final String DESCRIPTION_SUFFIX = ".description";
  private static final String VALUE_SUFFIX = ".value";
  private static final String FORMAT_SUFFIX = ".format";

  /**
   * Logger for this class and subclasses
   */
  protected final Log logger = LogFactory.getLog(getClass());
  private ReloadableResourceBundleMessageSource messageSource;
  private Map<String, String> baseNamePrefixes;
  private SimplePropertiesPersister propertiesPersister;

// --------------------- GETTER / SETTER METHODS ---------------------

  public Map getBaseNamePrefixes() {
    return baseNamePrefixes;
  }

  public void setMessageSource(ReloadableResourceBundleMessageSource messageSource) {
    this.messageSource = messageSource;
  }

  /**
   * Set the SimplePropertiesPersister to use for parsing and writing properties files.
   *
   * @param propertiesPersister propertiesPersister to be set
   */
  public void setPropertiesPersister(SimplePropertiesPersister propertiesPersister) {
    this.propertiesPersister = propertiesPersister;
  }

// ------------------------ INTERFACE METHODS ------------------------

// --------------------- Interface ConfigurationService ---------------------

  public String getValue(String code) {
    return messageSource.getMessage(code + VALUE_SUFFIX, null, null);
  }

  public int getValueInteger(String code) {
    String tmp = messageSource.getMessage(code + VALUE_SUFFIX, null, null);
    return Integer.parseInt(tmp);
  }

  public ConfigurationEntry getConfiguration(String code) {
    ConfigurationEntry ret = new ConfigurationEntry();
    ret.setId(code);
    ret.setDescriptionCode(messageSource.getMessage(code + DESCRIPTION_SUFFIX, null, null));
    ret.setValue(messageSource.getMessage(code + VALUE_SUFFIX, null, null));
    ret.setFormat(messageSource.getMessage(code + FORMAT_SUFFIX, null, null));
    return ret;
  }

  public List<ConfigurationEntry> getConfigurations(List<String> codes) {
    List<ConfigurationEntry> ret = new ArrayList<ConfigurationEntry>(codes.size());
    for (String code : codes) {
      ret.add(getConfiguration(code));
    }
    return ret;
  }

  public void setConfiguration(ConfigurationEntry configurationEntry) {

  }

  public void setConfigurations(List<ConfigurationEntry> configurationEntries) {
    // split configurationEntries into sets indexed by filename
    Map<String, List<ConfigurationEntry>> fileNames = new HashMap<String, List<ConfigurationEntry>>();
    for (ConfigurationEntry entry : configurationEntries) {
      String fileName = getAssociatedFileName(entry.getId());
      if (fileName != null) {
        if (!fileNames.containsKey(fileName)) {
          fileNames.put(fileName, new LinkedList<ConfigurationEntry>());
        }
        fileNames.get(fileName).add(entry);
      }
    }

    // for each file to be written: load the properties, add/update the provided values, save the file
    for (String fileName : fileNames.keySet()) {
      // write new values to map
      HashMap<String, String> config = new HashMap<String, String>();
      for (ConfigurationEntry entry : fileNames.get(fileName)) {
        config.put(entry.getId() + VALUE_SUFFIX, entry.getValue());
      }

      // persist values
      propertiesPersister.saveOrUpdate(config, fileName + PROPERTIES_SUFFIX);
    }
    messageSource.clearCache();
  }

// -------------------------- OTHER METHODS --------------------------

  private String getAssociatedFileName(String code) {
    for (String prefix : baseNamePrefixes.keySet()) {
      if (code.startsWith(prefix)) {
        return baseNamePrefixes.get(prefix);
      }
    }
    return null;
  }

  public void setBaseNamePrefixes(Map<String, String> baseNamePrefixes) {
    this.baseNamePrefixes = baseNamePrefixes;
    String[] baseNames = new String[baseNamePrefixes.size()];
    int i = 0;
    for (String baseName : baseNamePrefixes.values()) {
      baseNames[i++] = baseName;
    }
    messageSource.setBasenames(baseNames);
  }
}
